#coding=utf-8
# #####################################
# id : easyService
# sumarry : 守护进程服务类
#           eDaemon是真正意义上的守护进程，而eService是需要shell通过nohup方式执行
#
#           使用方法：
#                     _APPID_ = 'test'
#                     _SVC_ = easySvc.eDaemon(_APPID_) # _SVC_ = easySvc.eService(_APPID_)
#                     _SVC_.start()
#                     while(True): # 开始执行你的服务，服务一般是无条件运行，这里简单用打印做示例
#                         print 'something'
#                         time.sleep(1)
#
# author : Yoft <yoft@163.com>
# date : 2011-08-14
# version : 0.0.1
# history :
# #####################################

import os, sys, time
import signal

class eDaemon:
    def __init__(self, pname, **kwlist):
        self.conf = {'stdin' : '/dev/null',
                    'stdout' : os.environ['_ROOT_PATH_'] + '/var/log/' + pname + '/daemon.log',
                    'stderr' : os.environ['_ROOT_PATH_'] + '/var/log/' + pname + '/daemon.log'}
        self.conf.update(kwlist)
        self.pname = pname
        self.pfile = os.environ['_ROOT_PATH_'] + '/tmp/pid/' + pname + '.pid'
        if not os.path.isdir(os.path.dirname(self.pfile)):
            os.makedirs(os.path.dirname(self.pfile), 0755)
        for path in self.conf:
            if not os.path.isdir(os.path.dirname(self.conf[path])):
                os.makedirs(os.path.dirname(self.conf[path]), 0755)

    def start(self):
        try:
            pid = os.fork()
            if 0 < pid:
                sys.exit(0)
        except OSError, e:
            sys.stderr.write('fork #1 failed: (%d) %s\n' % (e.errno, e.strerror))
            sys.exit(1)
        os.chdir('/')
        os.umask(0)
        os.setsid()
        try:
            pid = os.fork()
            if 0 < pid:
                sys.exit(0)
        except OSError, e:
            sys.stderr.write('fork #2 failed: (%d) %s\n' % (e.errno, e.strerror))
            sys.exit(1)
        for f in sys.stdout, sys.stderr:
            f.flush()
        si = file(self.conf['stdin'], 'r')
        so = file(self.conf['stdout'], 'a+')
        se = file(self.conf['stderr'], 'a+', 0)
        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())
        pid = os.getpid()
        f = open(self.pfile, 'w')
        f.write(str(pid))
        f.close()
        return pid

    def status(self):
        if not os.path.isfile(self.pfile):
            return 0
        f = open(self.pfile, 'r')
        pid = f.read()
        f.close()
        fname = '/proc/' + pid + '/loginuid'
        if not os.path.isfile(fname):
            return 0
        if not os.stat(fname)[4] == os.getuid():
            return 0
        return int(pid)

    def stop(self):
        pid = self.status()
        if 0 == pid:
            return -1
        for i in range(40):
            os.kill(pid, signal.SIGTERM)
            time.sleep(0.1)
            if 0 == self.status():
                os.remove(self.pfile)
                return 0
        return -2

class eService:
    def __init__(self, pname):
        self.pname = pname
        self.pfile = os.environ['_ROOT_PATH_'] + '/tmp/pid/' + pname + '.pid'
        if not os.path.isdir(os.path.dirname(self.pfile)):
            os.makedirs(os.path.dirname(self.pfile), 0755)

    def start(self):
        pid = os.getpid()
        f = open(self.pfile, 'w')
        f.write(str(pid))
        f.close()
        return pid

    def status(self):
        if not os.path.isfile(self.pfile):
            return 0
        f = open(self.pfile, 'r')
        pid = f.read()
        f.close()
        fname = '/proc/' + pid + '/loginuid'
        if not os.path.isfile(fname):
            return 0
        if not os.stat(fname)[4] == os.getuid():
            return 0
        return int(pid)

    def stop(self):
        pid = self.status()
        if 0 == pid:
            return -1
        for i in range(40):
            os.kill(pid, signal.SIGTERM)
            time.sleep(0.1)
            if 0 == self.status():
                os.remove(self.pfile)
                return 0
        return -2